package com.xhsj.user.hr.process.overtime.service;

import com.google.common.collect.Maps;
import com.xhsj.user.hr.base.BaseParam;
import com.xhsj.user.hr.process.dto.processDefinition.HandleAuditDto;
import com.xhsj.user.hr.process.hrLeaveProcess.mapper.TbHrApprovalLeaveApplyMapper;
import com.xhsj.user.hr.process.hrLeaveProcess.query.CompensatoryLeaveTimeQuery;
import com.xhsj.user.hr.process.message.service.TbProjectMessageService;
import com.xhsj.user.hr.process.overtime.entity.TbHrOvertimeApply;
import com.xhsj.user.hr.process.overtime.entity.TbHrOvertimeApplyTime;
import com.xhsj.user.hr.process.overtime.mapper.TbHrOvertimeApplyMapper;
import com.xhsj.user.hr.process.overtime.query.OverTimeApplyFindAllQuery;
import com.xhsj.user.hr.process.overtime.service.TbHrOvertimeApplyService;
import com.xhsj.user.hr.base.BaseService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xhsj.user.hr.process.overtime.vo.FindUsageVo;
import com.xhsj.user.hr.process.processDefinition.query.ProcessNodeQuery;
import com.xhsj.user.hr.process.processDefinition.service.TbGlobalApprovalTaskService;
import com.xhsj.user.hr.process.query.ApprovalQuery;
import com.xhsj.user.security.entity.LoginUser;
import com.xhsj.user.hr.system.entity.TbHrLeaveSetting;
import com.xhsj.user.hr.system.entity.TbHrLeaveUsableLength;
import com.xhsj.user.hr.system.entity.TbHrZhaopinDemandApply;
import com.xhsj.user.hr.system.mapper.TbGlobalUserMapper;
import com.xhsj.user.hr.system.mapper.TbHrLeaveUsableLengthMapper;
import com.xhsj.user.hr.system.service.TbHrLeaveSettingService;
import com.xhsj.user.hr.system.service.TbHrLeaveUsableLengthService;
import com.xhsj.user.hr.system.vo.OverTimeApplyAuditTaskVo;
import com.xhsj.user.utils.DateUtils;
import com.xhsj.user.utils.MessageConstant;
import com.xhsj.user.utils.StringUtils;
import com.xhsj.user.utils.UserUtils;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.io.Serializable;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 加班申请 服务实现类
 * </p>
 *
 * @author suxiaolin
 * @since Oct 16, 2020 2:36:22 PM
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
//@CacheConfig(cacheNames = "TbHrOvertimeApply")
public class TbHrOvertimeApplyService extends BaseService<TbHrOvertimeApplyMapper, TbHrOvertimeApply> {
    @Autowired
    private TbHrOvertimeApplyMapper dao;

    @Autowired
    private TbHrOvertimeApplyTimeService tbHrOvertimeApplyTimeService;

    @Autowired
    private TbHrOvertimeApplyMapper tbHrOvertimeApplyMapper;

    @Autowired
    private TbGlobalApprovalTaskService tbGlobalApprovalTaskService;

    @Autowired
    private TbProjectMessageService tbProjectMessageService;

    @Autowired
    private TbGlobalUserMapper tbGlobalUserMapper;

    @Autowired
    private TbHrLeaveSettingService tbHrLeaveSettingService;

    @Autowired
    private TbHrApprovalLeaveApplyMapper tbHrApprovalLeaveApplyMapper;

    @Autowired
    private TbHrLeaveUsableLengthService tbHrLeaveUsableLengthService;
    @Autowired
    private TbHrLeaveUsableLengthMapper tbHrLeaveUsableLengthMapper;

    /**
     * 保存
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    //@CacheEvict(cacheNames="TbHrOvertimeApply", allEntries=true)
    public boolean saveData(TbHrOvertimeApply entity) throws Exception {

        boolean flag = false;
        boolean save = super.save(entity);
        if (save) {

            tbHrOvertimeApplyMapper.delByApplyId(entity.getId());
            List<TbHrOvertimeApplyTime> timeList = entity.getTimeList();
            HashMap<Object, Object> map = Maps.newHashMap();
            int total = 0;
            for (TbHrOvertimeApplyTime tbHrOvertimeApplyTime : timeList) {
                tbHrOvertimeApplyTime.setCreateBy(UserUtils.getLoginAppUser().getUserId());
                tbHrOvertimeApplyTime.setCreateDate(new Date());
                if (map.containsKey(tbHrOvertimeApplyTime.getStartDate())) {
                    throw new Exception(tbHrOvertimeApplyTime.getStartDate() + ",该日期重复,请调整！");
                } else {
                    map.put(tbHrOvertimeApplyTime.getStartDate(), 1);
                }

                tbHrOvertimeApplyTime.setOvertimeApplyId(entity.getId());
                int intHours = calculateHours(tbHrOvertimeApplyTime);
                total += intHours;
                tbHrOvertimeApplyTime.setWorkLength(intHours);
            }
            boolean b = tbHrOvertimeApplyTimeService.saveOrUpdateBatch(timeList);
            if (b) {
                entity.setWorkLength(total);
                this.startProcess(entity);
                return true;
            } else {
                throw new Exception("保存加班申请时间异常");
            }
        }

        return flag;
    }

    /**
     * 流程启动
     *
     * @author 苏小林
     * @date 2020/10/22 16:31
     * @param: entity
     */
    private void startProcess(TbHrOvertimeApply entity) throws Exception {
        LoginUser loginAppUser = UserUtils.getLoginAppUser();
        Long userId = loginAppUser.getUserId();
        HandleAuditDto handleAuditDto = new HandleAuditDto(entity.getId(), userId, userId, 10);
        handleAuditDto.setOpinionText(entity.getOpinionText());
        // 流程启动
        ProcessNodeQuery processNodeQuery = tbGlobalApprovalTaskService.startHandleAudit(handleAuditDto, entity.getOrganizationId());
        entity.setBusinessId(handleAuditDto.getBusinessId());
        // 修改招聘申请信息
        this.updateInfoById(entity, processNodeQuery);

        // 发送消息
        ApprovalQuery approvalQuery =
                new ApprovalQuery(handleAuditDto.getDataId(),
                        MessageConstant.MSG_1,
                        processNodeQuery.getUserId(),
                        processNodeQuery.getRoleIds(),
                        4,
                        UserUtils.getLoginAppUser().getUserId(),
                        UserUtils.getLoginAppUser().getFullName());
        this.sendMessage(approvalQuery);
    }

    /**
     * 修改信息
     *
     * @author 苏小林
     * @date 2020/10/22 16:32
     * @param: entity
     * @param: processNodeQuery
     */
    private void updateInfoById(TbHrOvertimeApply entity, ProcessNodeQuery processNodeQuery) {
        entity.setNodeId(processNodeQuery.getNodeId());
        entity.setNodeName(processNodeQuery.getNodeName());
        entity.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
        entity.setUpdateDate(new Date());
        this.updateById(entity);
    }

    public void sendMessage(ApprovalQuery approvalQuery) {
        //保存消息
        CompletableFuture<Void> f = CompletableFuture.runAsync(() -> {
            tbProjectMessageService.sendMessageCommon(approvalQuery);
        });
    }

    /**
     * 计算小时数
     *
     * @author 苏小林
     * @date 2020/10/21 9:24
     * @param: tbHrOvertimeApplyTime
     * @return: int
     */
    private int calculateHours(TbHrOvertimeApplyTime tbHrOvertimeApplyTime) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd");

        Date startDate = tbHrOvertimeApplyTime.getStartDate();
        Date stopDate = tbHrOvertimeApplyTime.getStopDate();
        String startTime = tbHrOvertimeApplyTime.getStartTime();
        String stopTime = tbHrOvertimeApplyTime.getStopTime();
        Date beforeTime = simpleDateFormat.parse(simpleDateFormat1.format(startDate) + " " + tbHrOvertimeApplyTime.getStartTime() + ":00");
        Date endTime = simpleDateFormat.parse(simpleDateFormat1.format(stopDate) + " " + tbHrOvertimeApplyTime.getStopTime() + ":00");
        long hours = (endTime.getTime() - beforeTime.getTime()) / (1000 * 60 * 60);

        String[] stt = startTime.split(":");
        String[] std = stopTime.split(":");
        int st = Integer.parseInt(stt[0]);
        int stp = Integer.parseInt(std[0]);
        if (st < 13 && stp >= 13) {
            hours = hours - 1;
        }
        return new Long(hours).intValue();
    }

    /**
     * 通过id获取数据
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    @Override
    //@Cacheable(key = "#id",sync = true)
    public TbHrOvertimeApply getById(Serializable id) {
        TbHrOvertimeApply byId = dao.getDataById(id);
        if (byId != null) {
            int totalLength = 0;
            QueryWrapper<TbHrOvertimeApplyTime> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("overtime_apply_id", byId.getId());
            List<TbHrOvertimeApplyTime> list = tbHrOvertimeApplyTimeService.list(queryWrapper);
            for (TbHrOvertimeApplyTime tbHrOvertimeApplyTime : list) {
                int workLength = tbHrOvertimeApplyTime.getWorkLength();
                totalLength += workLength;
            }
            byId.setTimeList(list);
//            byId.setDays(calculateDays(totalLength));
            byId.setDays(totalLength + "小时");
        }

        return byId;
    }

    /**
     * 计算天数
     *
     * @author 苏小林
     * @date 2020/10/21 9:33
     * @param: totalLength
     * @return: java.lang.String
     */
    private String calculateDays(int totalLength) {
        if (totalLength < 8) {
            return totalLength + "小时";
        }

        int i = totalLength % 8;
        if (i == 0) {
            int i1 = totalLength / 8;
            return i1 + "天";
        } else {
            int i1 = totalLength / 8;
            return i1 + "天" + i + "小时";
        }

    }

    /**
     * 通过id删除数据
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    @Override
    //@CacheEvict(cacheNames="TbHrOvertimeApply", allEntries=true)
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    /**
     * 批量删除数据
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    //@CacheEvict(cacheNames="SysDict", allEntries=true)
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        return super.removeByIds(idList);
    }

    /**
     * 分页查询数据
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    //@Cacheable(key = "#data",sync = true)
    public IPage<TbHrOvertimeApply> selectPage(Map<String, Object> data) {
        int currentPage = 1;
        if (!Objects.isNull(data.get("page"))) {
            currentPage = (Integer) data.get("page");
        }
        int pageSize = 20;
        if (!Objects.isNull(data.get("size"))) {
            pageSize = (Integer) data.get("size");
        }

        Page<TbHrOvertimeApply> page = new Page(currentPage, pageSize);
        TbHrOvertimeApply entity = new TbHrOvertimeApply();
        entity.setCreateBy(UserUtils.getLoginAppUser().getUserId());
        IPage<TbHrOvertimeApply> iPage = dao.findOverTimeApplyList(page, entity);
        for (TbHrOvertimeApply record : iPage.getRecords()) {
//            record.setDays(calculateDays(record.getWorkLength()));
            record.setDays(record.getWorkLength() + "小时");
        }
        return iPage;
    }

    /**
     * 查询所有数据
     *
     * @author suxiaolin
     * @date Oct 16, 2020 2:36:22 PM
     */
    @Override
    //@Cacheable(value = "TbHrOvertimeApply",sync = true)
    public List<TbHrOvertimeApply> selectAll() {
        return super.selectAll();
    }


    /**
     * 查询正在执行的任务
     *
     * @author 苏小林
     * @date 2020/10/22 16:59
     * @param: data
     * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.xhsj.user.hr.system.vo.OverTimeApplyAuditTaskVo>
     */
    public IPage<OverTimeApplyAuditTaskVo> findRunTask(BaseParam data) {
        Page<TbHrOvertimeApply> page = new Page(data.getPage(), data.getSize());

        Long userId = UserUtils.getLoginAppUser().getUserId();
        List<Long> roleIds = tbGlobalUserMapper.getRoleIdsByUserId(userId);
        return dao.findRunTask(page, userId, roleIds);
    }

    /**
     * 查询历史任务
     *
     * @author 苏小林
     * @date 2020/10/22 16:59
     * @param: data
     * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.xhsj.user.hr.system.vo.OverTimeApplyAuditTaskVo>
     */
    public IPage<OverTimeApplyAuditTaskVo> findHiTask(BaseParam data) {
        Page<TbHrOvertimeApply> page = new Page(data.getPage(), data.getSize());

        Long userId = UserUtils.getLoginAppUser().getUserId();
        return dao.findHiTask(page, userId);
    }

    /**
     * 流程审核
     *
     * @author 苏小林
     * @date 2020/10/22 17:55
     * @param: handleAuditDto
     */
    public void processAudit(HandleAuditDto handleAuditDto) throws Exception {
        ProcessNodeQuery processNodeQuery = tbGlobalApprovalTaskService.handleAudit(handleAuditDto);

        TbHrOvertimeApply entity = new TbHrOvertimeApply();
        entity.setId(handleAuditDto.getDataId());
        entity.setBusinessId(handleAuditDto.getBusinessId());
        // 修改加班申请
        this.updateInfoById(entity, processNodeQuery);
        // 审核完成保存加班可用时长
        if ("完结".equals(processNodeQuery.getNodeName())) {

            QueryWrapper<TbHrOvertimeApplyTime> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("overtime_apply_id", handleAuditDto.getDataId());
            List<TbHrOvertimeApplyTime> list = tbHrOvertimeApplyTimeService.list(queryWrapper);

            saveOvertimeUsable(list, handleAuditDto.getProposerId(), true);
        }
        String fullName = tbHrApprovalLeaveApplyMapper.getFullNameByDataId(handleAuditDto.getDataId(),"tb_hr_overtime_apply");


        // 发送消息
        ApprovalQuery approvalQuery =
                new ApprovalQuery(handleAuditDto.getDataId(), MessageConstant.MSG_1, processNodeQuery.getUserId(),
                        processNodeQuery.getRoleIds(), 4, UserUtils.getLoginAppUser().getUserId(),fullName);
        this.sendMessage(approvalQuery);
    }

    // 保存可用时间
    public void saveOvertimeUsable(List<TbHrOvertimeApplyTime> list, Long createBy, boolean updateAllOverTime) throws ParseException {

        LocalDate now = LocalDate.now();
        // 获取当前年
        int currentYear = now.getYear();
        int currentNumber = 0; // 本年加班数
        int nextNumber = 0; // 下一年加班数
        for (TbHrOvertimeApplyTime tbHrOvertimeApplyTime : list) {
            int startYear = DateUtils.date2LocalDate(tbHrOvertimeApplyTime.getStartDate()).getYear();
            int stopYear = DateUtils.date2LocalDate(tbHrOvertimeApplyTime.getStopDate()).getYear();
            // 本年度加班
            if (startYear == currentYear && stopYear == currentYear) {
                currentNumber += tbHrOvertimeApplyTime.getWorkLength();
            }

            if (startYear == currentYear + 1 && stopYear == currentYear + 1) {
                nextNumber += tbHrOvertimeApplyTime.getWorkLength();
            }

            if (startYear == currentYear && stopYear == currentYear + 1) {

                LocalDate stopDate = DateUtils.date2LocalDate(tbHrOvertimeApplyTime.getStopDate());
                String stopTime = tbHrOvertimeApplyTime.getStopTime();
                String format = stopDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date parse = simpleDateFormat.parse(format + " " + stopTime + ":00");
                Date parse1 = simpleDateFormat.parse(format + " 00:00:00");

                Long l = (parse.getTime() - parse1.getTime()) / (1 * 1000 * 60 * 60);
                int i = l.intValue();
                // 下一年的加班数
                nextNumber += i;
                // 本年度加班数
                currentNumber += (tbHrOvertimeApplyTime.getWorkLength() - i);
            }
        }

        if (currentNumber != 0) {
            saveNumber(createBy, currentYear, currentNumber, updateAllOverTime);
        }

        if (nextNumber != 0) {
            saveNumber(createBy, currentYear + 1, nextNumber, updateAllOverTime);
        }
    }

    private void saveNumber(Long createBy, int currentYear, int currentNumber, boolean updateAllOverTime) {
        int count = tbHrLeaveUsableLengthService.getByUserIdAndYear(currentYear + "", createBy);
        if (count == 0) {
            TbHrLeaveUsableLength tbHrLeaveUsableLength = new TbHrLeaveUsableLength();
            tbHrLeaveUsableLength.setYear(currentYear + "");
            tbHrLeaveUsableLength.setOverTimeUsable(currentNumber);
            tbHrLeaveUsableLength.setAllOverTime(currentNumber);
            tbHrLeaveUsableLength.setCreateBy(createBy);
            tbHrLeaveUsableLengthMapper.insert(tbHrLeaveUsableLength);
        } else {
            int allOverNumber = currentNumber;
            if (!updateAllOverTime) { // 如果不需要更新总时间
                allOverNumber = 0;
            }
            tbHrLeaveUsableLengthMapper.updateByUserIdAndYear(currentYear + "", createBy, currentNumber, allOverNumber);
        }
    }

    public void reSubmit(TbHrOvertimeApply data) throws Exception {
        Long processTaskId = data.getProcessTaskId();
        tbGlobalApprovalTaskService.delById(processTaskId);
        this.saveData(data);
    }

    /**
     * 查询所有加班申请数据
     *
     * @author 苏小林
     * @date 2020/10/23 13:25
     * @return: java.util.List<com.xhsj.user.hr.process.overtime.entity.TbHrOvertimeApply>
     */
    public IPage<TbHrOvertimeApply> findAllOverTimeApplyList(OverTimeApplyFindAllQuery data) {
        Page<TbHrOvertimeApply> page = new Page<>(data.getPage(), data.getSize());
        IPage<TbHrOvertimeApply> iPage = dao.findAllOverTimeApplyList(page, data.getOrganizationId(), data.getPositionId(), data.getName());
        return iPage;
    }

    /**
     * 查询加班使用情况
     *
     * @author 苏小林
     * @date 2020/10/23 15:43
     * @param: data
     * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.xhsj.user.hr.process.overtime.vo.FindUsageVo>
     */
    public IPage<FindUsageVo> findUsage(OverTimeApplyFindAllQuery data) throws ParseException {


        if (StringUtils.isBlank(data.getYear())) {
            LocalDateTime now = LocalDateTime.now();
            String yyyy = now.format(DateTimeFormatter.ofPattern("yyyy"));
            data.setYear(yyyy);
        }

        FindUsageVo findUsageVo = new FindUsageVo(data.getName(), data.getOrganizationId(), data.getPositionId());
        findUsageVo.setYear(data.getYear());
        Page<TbHrOvertimeApply> page = new Page<>(data.getPage(), data.getSize());
        IPage<FindUsageVo> iPage = dao.findUsage(page, findUsageVo);
        List<FindUsageVo> records = iPage.getRecords();
        if (records != null) {

            for (FindUsageVo record : records) {
                CompensatoryLeaveTimeQuery overTimeUsableLength = tbHrLeaveUsableLengthService.getOverTimeUsableLength(record.getCreateBy(), LocalDate.now());
                if (overTimeUsableLength !=null) {
                    record.setTotalLength(overTimeUsableLength.getHrOvertime());
                    record.setUseLength(overTimeUsableLength.getHrOvertime()-overTimeUsableLength.getSurplusTime());
                }
            }

        }

        return iPage;
    }

    public static Date calculateDate(String overTimeExpire) throws ParseException {

        String[] split = overTimeExpire.split("-");
        String s = split[0];
        // 截止月
        int i = Integer.parseInt(s);
        // 当前月
        int monthValue = LocalDate.now().getMonthValue();

        int year = LocalDate.now().getYear();

        String date = year + "-" + overTimeExpire;

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = simpleDateFormat.parse(date);

        Calendar cal = Calendar.getInstance();
        cal.setTime(parse);//设置起时间

        if (monthValue > i) {
            cal.add(Calendar.YEAR, 1);//增加一年
            return cal.getTime();
        } else {
            return parse;
        }
    }


    public static void main(String[] args) throws ParseException {

        String ss = "11-31";

        // 截止月
        int i = Integer.parseInt("11");
        // 当前月
        int monthValue = LocalDate.now().getMonthValue();
        int year = LocalDate.now().getYear();

        String date = year + "-" + ss;

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = simpleDateFormat.parse(date);

        Calendar cal = Calendar.getInstance();
        cal.setTime(parse);//设置起时间
        System.err.println("截止月:" + i);
        System.err.println("当前月:" + monthValue);

        if (monthValue > i) {
            cal.add(Calendar.YEAR, 1);//增加一年
            System.err.println(cal.getTime());
        } else {
            System.err.println(parse);
        }

    }

    /**
     * 查询年度用户所有的加班详情
     *
     * @author 苏小林
     * @date 2020/10/26 11:18
     * @param: userId
     * @param: year
     * @return: java.util.List<com.xhsj.user.hr.process.overtime.entity.TbHrOvertimeApplyTime>
     */
    public List<TbHrOvertimeApplyTime> findDetailByUserId(String userId, String year) {

        if (StringUtils.isBlank(year)) {
            LocalDateTime now = LocalDateTime.now();
            year = now.format(DateTimeFormatter.ofPattern("yyyy"));
        }

        List<TbHrOvertimeApplyTime> list = dao.findDetailByUserId(userId, year);

        return list;
    }

    /**
     * 作废
     * @author 苏小林
     * @date 2020/11/2 17:36
     * @param: processTaskId
     * @param: dataId
     */
    public void disable(Long processTaskId, Long dataId) throws Exception{
        tbGlobalApprovalTaskService.delById(processTaskId);
        dao.delById(dataId);
    }
}
